import serial
from PyQt5.QtWidgets import (
    QWidget, QLabel, QComboBox,
    QLineEdit, QPushButton, QTextEdit, QVBoxLayout,
    QHBoxLayout, QMessageBox, QCheckBox, QTableWidget, QTableWidgetItem, QHeaderView
)
from PyQt5.QtCore import QTimer, Qt

from app.map_window import MapWindow

from app.ais_decoder import AisDecoder
from app.serial_handler import SerialHandler


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("AIS串口工具")
        self.setGeometry(100, 100, 500, 400)

        self.last_rows = 0

        self.decoder = AisDecoder()
        self.map_window = None

        self.init_ui()
        self.realtime_ais_decode = False
        self.update_ports()

        self.AIS_FIELD_MAP = {
            "消息类型": "msg_type",
            "MMSI": "mmsi",
            "经纬度": ("lon", "lat"),
            "航速(节)": "speed",
            "航向(°)": "course",
            "艏向(°)": "heading",
            "转动角": "turn"
        }

    def init_ui(self):
        main_widget = QWidget()
        main_layout = QHBoxLayout()

        left_layout = QVBoxLayout()
        right_layout = QVBoxLayout()

        left_widget = QWidget()
        right_widget = QWidget()

        left_layout.addLayout(self.create_config_group())
        left_layout.addLayout(self.create_send_receive_area())
        left_widget.setLayout(left_layout)

        right_layout.addLayout(self.create_decode_area())
        right_widget.setLayout(right_layout)

        main_layout.addWidget(left_widget, 4)
        main_layout.addWidget(right_widget, 5)

        main_widget.setLayout(main_layout)

        layout = QVBoxLayout(self)
        layout.addWidget(main_widget)
        self.setLayout(layout)

    def create_config_group(self):
        layout = QVBoxLayout()
        # 打开端口按钮
        self.open_button = QPushButton("打开端口")
        self.open_button.clicked.connect(self.toggle_port)

        layout.addLayout(self.create_port_selection())
        layout.addLayout(self.create_baud_selection())
        layout.addWidget(self.open_button)

        return layout

    def create_port_selection(self):
        # 串口选择
        port_layout = QHBoxLayout()
        self.port_combo = QComboBox()
        label = QLabel("串口号:")
        label.setFixedWidth(60)
        self.refresh_button = QPushButton("刷新端口")
        self.refresh_button.clicked.connect(self.update_ports)
        port_layout.addWidget(label, 1)
        port_layout.addWidget(self.port_combo, 3)
        port_layout.addWidget(self.refresh_button, 1)
        return port_layout

    def create_baud_selection(self):
        # 波特率选择
        baud_layout = QHBoxLayout()
        self.baud_combo = QComboBox()
        label = QLabel("波特率:")
        label.setFixedWidth(60)
        self.baud_combo.addItems(["9600", "19200", "38400", "57600", "115200"])
        baud_layout.addWidget(label, 1)
        baud_layout.addWidget(self.baud_combo, 3)
        baud_layout.addStretch()
        return baud_layout

    def create_send_receive_area(self):
        # 数据显示区域
        layout = QVBoxLayout()

        # 接收显示
        self.output_area = QTextEdit()
        self.output_area.setReadOnly(True)

        self.clear_button = QPushButton("清空")
        self.clear_button.clicked.connect(self.clear_data)

        self.realtime_checkbox = QCheckBox("实时解析 AIS")
        self.realtime_checkbox.setChecked(False)  # 默认关闭
        self.realtime_checkbox.stateChanged.connect(self.toggle_realtime_decode)

        button_layout = QVBoxLayout()
        button_layout.addWidget(self.clear_button)
        button_layout.addWidget(self.realtime_checkbox)

        receive_layout = QHBoxLayout()
        receive_layout.addWidget(self.output_area)
        receive_layout.addLayout(button_layout)

        # 发送输入
        self.send_input = QLineEdit()
        self.send_button = QPushButton("发送")
        self.send_button.clicked.connect(self.send_data)

        send_layout = QHBoxLayout()
        send_layout.addWidget(self.send_input)
        send_layout.addWidget(self.send_button)

        # 布局组合
        layout.addWidget(QLabel("接收数据:"))
        layout.addLayout(receive_layout)
        layout.addWidget(QLabel("发送数据:"))
        layout.addLayout(send_layout)

        # 定时读取串口数据
        self.timer = QTimer()
        self.timer.timeout.connect(self.read_data)
        return layout

    def create_decode_area(self):
        layout = QVBoxLayout()

        self.ais_table = QTableWidget()
        self.ais_table.setColumnCount(7)
        self.ais_table.setHorizontalHeaderLabels(["消息类型", "MMSI", "经纬度", "航速", "航向", "艏向", "转动角"])
        self.ais_table.verticalHeader().setVisible(False)  # 隐藏行号

        self.ais_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.ais_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Fixed)  # 经纬度列固定
        self.ais_table.setColumnWidth(2, 200)

        self.clear_button = QPushButton("清空")
        self.clear_button.clicked.connect(self.clear_ais_table)

        self.show_map_button = QPushButton("显示地图")
        self.show_map_button.clicked.connect(self.show_ais_map)
        layout.addWidget(self.show_map_button)

        layout.addWidget(self.ais_table)
        layout.addWidget(self.clear_button)

        return layout

    def update_ports(self):
        """自动检测可用串口"""
        import serial.tools.list_ports
        ports = list(serial.tools.list_ports.comports())
        self.port_combo.clear()
        for port in ports:
            if port.hwid == 'n/a':
                continue
            self.port_combo.addItem(port.device)

    def toggle_port(self):
        port = self.port_combo.currentText()
        baud = int(self.baud_combo.currentText())
        if hasattr(self, 'serial_handler'):
            self.serial_handler.close()
            del self.serial_handler
            self.timer.stop()
            self.open_button.setText("打开端口")
            # 启用控件（串口关闭后允许修改）
            self.port_combo.setEnabled(True)
            self.baud_combo.setEnabled(True)
        else:
            self.serial_handler = SerialHandler(port, baud)
            try:
                self.serial_handler.open()
                self.open_button.setText("关闭端口")
                self.timer.start(100)
                # 禁用控件（串口打开后不允许修改）
                self.port_combo.setEnabled(False)
                self.baud_combo.setEnabled(False)
            except Exception as e:
                QMessageBox.warning(self, "错误", str(e))

    def send_data(self):
        if self.serial_handler.is_open:
            data = self.send_input.text()
            self.serial_handler.write(data)
            self.output_area.append(f">>> {data}")
            self.send_input.clear()
        else:
            QMessageBox.warning(self, "警告", "请先打开串口")

    def clear_data(self):
        self.output_area.clear()

    def clear_ais_table(self):
        self.ais_table.setRowCount(0)

    def read_data(self):
        data = self.serial_handler.read_line()
        if data:
            self.output_area.append(f"<<< {data}")

            if self.realtime_ais_decode and "!AIVDM" in data:
                try:
                    # 提取 AIS 消息内容
                    ais_dict = self.decoder.decode_with_cache(data)
                    # 更新右侧表格
                    if ais_dict:
                        self.update_ais_table(ais_dict)

                except Exception as e:
                    self.output_area.append(f"[AIS 解码失败]: {e}")

    def toggle_realtime_decode(self, state):
        self.realtime_ais_decode = (state == Qt.Checked)

    def update_ais_table(self, ais_data):
        """
        :param ais_data: dict 或 list of dict，包含 AIS 解析结果
        """

        if isinstance(ais_data, dict):
            ais_data = [ais_data]

        for data in ais_data:
            current_row = self.ais_table.rowCount()
            self.ais_table.insertRow(current_row)

            for col_idx, (col_name, key) in enumerate(self.AIS_FIELD_MAP.items()):
                if col_name == "经纬度":
                    lon = data.get(key[0], "-")
                    lat = data.get(key[1], "-")
                    value = f"{lat}, {lon}"
                else:
                    value = data.get(key, "-")

                # 如果是枚举类型，取描述文本
                if hasattr(value, 'name'):
                    value = value.name

                # 布尔值转文字
                elif isinstance(value, bool):
                    value = "是" if value else "否"

                # 数值保留合适格式
                elif isinstance(value, float):
                    value = round(value, 2)

                self.ais_table.setItem(current_row, col_idx, QTableWidgetItem(str(value)))

        self.ais_table.scrollToBottom()

    def get_map_data(self):
        """获取当前表格中的 AIS 数据，并返回一个列表，每个元素是一个字典，包含 AIS 数据"""
        ais_data_list = []
        for row in range(self.last_rows, self.ais_table.rowCount()):
            item_lat_lon = self.ais_table.item(row, 2)
            if item_lat_lon and item_lat_lon.text() != "-, -":
                try:
                    lat_str, lon_str = item_lat_lon.text().split(",")
                    lat = float(lat_str.strip())
                    lon = float(lon_str.strip())

                    ais_data = {
                        "mmsi": self.ais_table.item(row, 1).text(),
                        "lat": lat,
                        "lon": lon,
                        "speed": float(self.ais_table.item(row, 3).text()) if self.ais_table.item(row, 3) else 0,
                        "course": float(self.ais_table.item(row, 4).text()) if self.ais_table.item(row, 4) else 0
                    }
                    ais_data_list.append(ais_data)
                except (ValueError, AttributeError):
                    continue
        self.last_rows = self.ais_table.rowCount() - 1
        return ais_data_list

    def refresh_ais_table(self):
        data = self.get_map_data()
        if self.map_window and not getattr(self.map_window, 'isClosed', False):
            self.map_window.update_map(data)

    def show_ais_map(self):
        """打开地图窗口，并传递当前表格中的 AIS 数据"""
        if not self.map_window or getattr(self.map_window, "isClosed", False):
            self.map_window = MapWindow()
            self.map_window.setAttribute(Qt.WA_DeleteOnClose)
            self.map_window.isClosed = False  # 自定义标志位跟踪状态

            # 连接关闭事件
            self.map_window.destroyed.connect(lambda: setattr(self.map_window, "isClosed", True))
            # 关闭时释放资源

        # 获取当前表格中的所有 AIS 数据
        ais_data_list = self.get_map_data()

        # 更新地图
        if ais_data_list:
            self.map_window.update_map(ais_data_list)

        self.refresh_ais_map = QTimer()
        self.refresh_ais_map.timeout.connect(self.refresh_ais_table)
        self.refresh_ais_map.start(3000)

        # 显示地图窗口
        self.map_window.show()
        self.map_window.raise_()
